
package com.dremio.exec.store.jdbc.conf;

import com.dremio.exec.catalog.conf.DisplayMetadata;
import com.dremio.exec.catalog.conf.NotMetadataImpacting;
import com.dremio.exec.catalog.conf.Secret;
import com.dremio.exec.catalog.conf.SourceType;
import com.dremio.exec.store.jdbc.CloseableDataSource;
import com.dremio.exec.store.jdbc.DataSources;
import com.dremio.exec.store.jdbc.JdbcPluginConfig;
import com.dremio.exec.store.jdbc.dialect.arp.ArpDialect;
import com.dremio.options.OptionManager;
import com.dremio.security.CredentialsService;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.google.common.annotations.VisibleForTesting;
import io.protostuff.Tag;
import org.hibernate.validator.constraints.NotBlank;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import static com.google.common.base.Preconditions.checkNotNull;

/**
 * Configuration for KINGBASE source.
 */
@SourceType(value = "KINGBASE", label = "KingBase ES")
public class KingbaseConf extends AbstractArpConf<KingbaseConf> {

    private static final Logger logger = LoggerFactory.getLogger(KingbaseConf.class);

    private static final String ARP_FILENAME = "arp/implementation/kingbase-arp.yaml";

    private static final ArpDialect ARP_DIALECT = AbstractArpConf.loadArpFile(ARP_FILENAME, (ArpDialect::new));
    private static final String DRIVER = "com.kingbase8.Driver";

    @NotBlank
    @Tag(1)
    @DisplayMetadata(label = "Host")
    public String host;

    @NotBlank
    @Tag(2)
    @DisplayMetadata(label = "Port")
    public String port;

    @NotBlank
    @Tag(3)
    @DisplayMetadata(label = "Username")
    public String username;

    @NotBlank
    @Tag(4)
    @Secret
    @DisplayMetadata(label = "Password")
    public String password;

    @NotBlank
    @Tag(5)
    @DisplayMetadata(label = "Database")
    public String database;

    @Tag(6)
    @DisplayMetadata(label = "Encrypt connection")
    public boolean useSsl = false;

    @Tag(8)
    @DisplayMetadata(label = "Record fetch size")
    @NotMetadataImpacting
    public int fetchSize = 500;

    @Tag(9)
    @NotMetadataImpacting
    @JsonIgnore
    public boolean enableExternalQuery = false;

    @Tag(10)
    @DisplayMetadata(label = "Maximum idle connections")
    @NotMetadataImpacting
    public int maxIdleConns = 8;

    @Tag(11)
    @DisplayMetadata(label = "Connection idle time (s)")
    @NotMetadataImpacting
    public int idleTimeSec = 60;



    @VisibleForTesting
    public String toJdbcConnectionString() {
        final String host = checkNotNull(this.host, "Missing host.");
        final String port = checkNotNull(this.port, "Missing port.");
        final String username = checkNotNull(this.username, "Missing username.");
        final String password = checkNotNull(this.password, "Missing password.");
        final String database = checkNotNull(this.database, "Missing database.");

        logger.info(String.format("JDBC URL ---- jdbc:kingbase8://%s:%s/%s", host, port, database));
        return String.format("jdbc:kingbase8://%s:%s/%s", host, port, database);
    }

    private CloseableDataSource newDataSource() {
        return DataSources.newGenericConnectionPoolDataSource(DRIVER,
                toJdbcConnectionString(),
                username,
                password,
                null,
                DataSources.CommitMode.DRIVER_SPECIFIED_COMMIT_MODE);
    }

    @Override
    public ArpDialect getDialect() {
        return ARP_DIALECT;
    }

    @VisibleForTesting
    public static ArpDialect getDialectSingleton() {
        return ARP_DIALECT;
    }

    @Override
    public JdbcPluginConfig buildPluginConfig(JdbcPluginConfig.Builder builder, CredentialsService credentialsService, OptionManager optionManager) {
        return builder
                .withDialect(getDialect())
                .withDatasourceFactory(this::newDataSource)
                .withShowOnlyConnDatabase(false)
                .withFetchSize(this.fetchSize)
                .withAllowExternalQuery(enableExternalQuery)
                .build();
    }
}
